package com.ymx.darling.datasource.routing.dialect;

import com.ymx.darling.datasource.routing.RoutingDataSourceProperties;
import com.ymx.darling.dialect.*;
import com.ymx.darling.exception.DarlingException;
import com.ymx.darling.mapper.proxy.DarlingProxyFactory;
import com.ymx.darling.util.ReflectUtil;
import com.ymx.darling.util.StringUtil;

import java.util.HashMap;
import java.util.Map;

/**
 * 方言自动配置类
 * @author 爱Java的小于
 */
public class RoutingDialectAutoConfigurationUtil {
    /**
     * 根据{@code RoutingDataSourceProperties}中的配置信息自动配置多数据源的方言
     * @param routingDataSourceProperties dsp
     */
    public static void registerDialect(RoutingDataSourceProperties routingDataSourceProperties) {
        Map<String, Dialect> dialectMap = new HashMap<>();
        // 获取全局默认数据源
        Class<? extends Dialect> defaultDialect = routingDataSourceProperties.getDialect();
        routingDataSourceProperties.getRouting().forEach((dsKey, property) -> {
            Class<? extends Dialect> slaveDialect = property.getDialect();
            if (slaveDialect == null) {
                if (defaultDialect != null) {
                    slaveDialect = defaultDialect;
                } else {
                    slaveDialect = getDialectByUrl(property.getUrl());
                }
            }
            if (slaveDialect == null) {
                throw new DarlingException(String.format("darling无法识别并自动配置数据源'%s'的方言", dsKey));
            }
            dialectMap.put(dsKey, ReflectUtil.newInstance(slaveDialect));
        });

        // 加载多数据源方言
        String primary = routingDataSourceProperties.getPrimary();
        // 创建一个方言的代理实例 保证不同数据源获取的是自己的方言
        Dialect routingDialect = DarlingProxyFactory.newInstance(Dialect.class, new DialectProxy(dialectMap, primary));
        DialectManager.setDialect(routingDialect);
    }


    /**
     * 根据jdbc的url返回指定数据库的方言
     * @param url url
     * @return 只支持(mysql,db2,sqlserver,oracle,postgresql,dm.kingbase,sqlite)八种数据库方言的返回 其他返回null
     */
    private static Class<? extends Dialect> getDialectByUrl(String url) {
        if (StringUtil.isNoNull(url)) {
            if (url.startsWith("jdbc:mysql:")) {
                return MySqlDialect.class;
            } else if (url.startsWith("jdbc:oracle:")) {
                return OracleDialect.class;
            } else if (url.startsWith("jdbc:db2:")) {
                return DB2Dialect.class;
            } else if (url.startsWith("jdbc:sqlserver:")) {
                return SqlServerDialect.class;
            } else if (url.startsWith("jdbc:postgresql:")) {
                return PostgresDialect.class;
            } else if (url.startsWith("jdbc:dm:")) {
                return DmDialect.class;
            } else if (url.startsWith("jdbc:kingbase8:")) {
                return KingbaseDialect.class;
            } else if (url.startsWith("jdbc:sqlite:")) {
                return SQLiteDialect.class;
            }
        }
        return null;
    }
}
